﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Services.Protocols;
using System.Xml;
using System.Reflection;

namespace Services
{
    public sealed class AuthenticationModule : IHttpModule
    {
        //private EventHandler<AuthenticationEventArgs> _authHandler;

        //public event EventHandler<AuthenticationEventArgs> Authenticate
        //{
        //    add { _authHandler += value; }
        //    remove { _authHandler -= value; }
        //}

        public void Dispose()
        {

        }

        public void Init(HttpApplication app)
        {
            app.AuthenticateRequest += AppAuthenticationRequest;
        }

        private void AppAuthenticationRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            HttpContext context = app.Context;
            Stream stream = context.Request.InputStream;
            long pos = stream.Position;

            var httpSoapAction = context.Request.ServerVariables["HTTP_SOAPACTION"];
            if (httpSoapAction == null) return;

            string accessToken;

            try
            {
                var dom = new XmlDocument();
                dom.Load(stream);
                stream.Position = pos;
                string action = dom.GetElementsByTagName("soap:Body")[0].ChildNodes[0].Name;
                bool isNeedAccessToken = IsNeedAccessToken(action);
                if (isNeedAccessToken)
                {
                    accessToken = dom.GetElementsByTagName("AccessToken").Item(0).InnerText;
                }

            }
            catch (Exception ex)
            {
                stream.Position = pos;
                //检查是否标记了Authorize
                SoapException exception = new SoapException("缺失认证客户身份的必要信息", new XmlQualifiedName("非法请求"), ex);
                throw exception;
            }

            //根据用户缓存信息，获取用户身份信息
            //AuthenticationEventArgs args = new AuthenticationEventArgs(context, accessToken);
            //if (args.User != null) args.Context.User = args.User;
            //app.Context.User
        }

        private bool IsNeedAccessToken(string methodName) 
        {
            Assembly assembly = Assembly.GetExecutingAssembly();//当前执行程序集
            var types = assembly.GetTypes();
            foreach (var t in types)
            {
                if (t.Name == "TestServices")
                {
                    MethodInfo mi = t.GetMethod(methodName);
                    object[] attributes = mi.GetCustomAttributes(false);
                    foreach (Attribute attribute in attributes)
                    {
                        if (attribute is SoapHeaderAttribute &&
                            (attribute as SoapHeaderAttribute).MemberName == "accessToken")
                            return true;
                    }
                }
            }
            return false;
        }
    }
}